<?php
+use MediaWiki\MediaWikiServices;
use MediaWiki\Storage\BlobStoreFactory;
+use MediaWiki\Storage\MutableRevisionRecord;
+use MediaWiki\Storage\RevisionAccessException;
+use MediaWiki\Storage\RevisionRecord;
use MediaWiki\Storage\RevisionStore;
+use MediaWiki\Storage\SlotRecord;
use MediaWiki\Storage\SqlBlobStore;
use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\LoadBalancer;
$this->assertNull( $rev->getContent(), 'no content object should be available' );
}
+ /**
+ * @covers Revision::__construct
+ * @covers \MediaWiki\Storage\RevisionStore::newMutableRevisionFromArray
+ */
+ public function testConstructFromArrayWithBadPageId() {
+ Wikimedia\suppressWarnings();
+ $rev = new Revision( [ 'page' => 77777777 ] );
+ $this->assertSame( 77777777, $rev->getPage() );
+ Wikimedia\restoreWarnings();
+ }
+
public function provideConstructFromArray_userSetAsExpected() {
yield 'no user defaults to wgUser' => [
[
$assertions( $this, $rev );
}
+ /**
+ * @covers Revision::__construct
+ * @covers \MediaWiki\Storage\RevisionStore::newMutableRevisionFromArray
+ */
+ public function testConstructFromRowWithBadPageId() {
+ $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
+ $this->overrideMwServices();
+ Wikimedia\suppressWarnings();
+ $rev = new Revision( (object)[ 'rev_page' => 77777777 ] );
+ $this->assertSame( 77777777, $rev->getPage() );
+ Wikimedia\restoreWarnings();
+ }
+
public function provideGetRevisionText() {
yield 'Generic test' => [
'This is a goat of revision text.',
$cache = $this->getWANObjectCache();
- $blobStore = new RevisionStore( $lb, $this->getBlobStore(), $cache );
+ $blobStore = new RevisionStore(
+ $lb,
+ $this->getBlobStore(),
+ $cache,
+ MediaWikiServices::getInstance()->getCommentStore()
+ );
return $blobStore;
}
* @covers Revision::loadFromTitle
*/
public function testLoadFromTitle() {
+ $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
+ $this->overrideMwServices();
$title = $this->getMockTitle();
$conditions = [
);
}
+ private function overrideCommentStore() {
+ $mockStore = $this->getMockBuilder( CommentStore::class )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $mockStore->expects( $this->any() )
+ ->method( 'getFields' )
+ ->willReturn( [ 'commentstore' => 'fields' ] );
+ $mockStore->expects( $this->any() )
+ ->method( 'getJoin' )
+ ->willReturn( [
+ 'tables' => [ 'commentstore' => 'table' ],
+ 'fields' => [ 'commentstore' => 'field' ],
+ 'joins' => [ 'commentstore' => 'join' ],
+ ] );
+
+ $this->setService( 'CommentStore', $mockStore );
+ }
+
public function provideSelectFields() {
yield [
true,
'rev_len',
'rev_parent_id',
'rev_sha1',
- 'rev_comment_text' => 'rev_comment',
- 'rev_comment_data' => 'NULL',
- 'rev_comment_cid' => 'NULL',
+ 'commentstore' => 'fields',
'rev_content_format',
'rev_content_model',
]
'rev_len',
'rev_parent_id',
'rev_sha1',
- 'rev_comment_text' => 'rev_comment',
- 'rev_comment_data' => 'NULL',
- 'rev_comment_cid' => 'NULL',
+ 'commentstore' => 'fields',
]
];
}
/**
* @dataProvider provideSelectFields
* @covers Revision::selectFields
- * @todo a true unit test would mock CommentStore
*/
public function testSelectFields( $contentHandlerUseDB, $expected ) {
$this->hideDeprecated( 'Revision::selectFields' );
$this->setMwGlobals( 'wgContentHandlerUseDB', $contentHandlerUseDB );
- $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
+ $this->overrideCommentStore();
$this->assertEquals( $expected, Revision::selectFields() );
}
'ar_len',
'ar_parent_id',
'ar_sha1',
- 'ar_comment_text' => 'ar_comment',
- 'ar_comment_data' => 'NULL',
- 'ar_comment_cid' => 'NULL',
+ 'commentstore' => 'fields',
'ar_content_format',
'ar_content_model',
]
'ar_len',
'ar_parent_id',
'ar_sha1',
- 'ar_comment_text' => 'ar_comment',
- 'ar_comment_data' => 'NULL',
- 'ar_comment_cid' => 'NULL',
+ 'commentstore' => 'fields',
]
];
}
/**
* @dataProvider provideSelectArchiveFields
* @covers Revision::selectArchiveFields
- * @todo a true unit test would mock CommentStore
*/
public function testSelectArchiveFields( $contentHandlerUseDB, $expected ) {
$this->hideDeprecated( 'Revision::selectArchiveFields' );
$this->setMwGlobals( 'wgContentHandlerUseDB', $contentHandlerUseDB );
- $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
+ $this->overrideCommentStore();
$this->assertEquals( $expected, Revision::selectArchiveFields() );
}
}
public function provideGetArchiveQueryInfo() {
- yield 'wgContentHandlerUseDB false, wgCommentTableSchemaMigrationStage OLD' => [
- [
- 'wgContentHandlerUseDB' => false,
- 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
- ],
- [
- 'tables' => [ 'archive' ],
- 'fields' => [
- 'ar_id',
- 'ar_page_id',
- 'ar_namespace',
- 'ar_title',
- 'ar_rev_id',
- 'ar_text',
- 'ar_text_id',
- 'ar_timestamp',
- 'ar_user_text',
- 'ar_user',
- 'ar_minor_edit',
- 'ar_deleted',
- 'ar_len',
- 'ar_parent_id',
- 'ar_sha1',
- 'ar_comment_text' => 'ar_comment',
- 'ar_comment_data' => 'NULL',
- 'ar_comment_cid' => 'NULL',
- ],
- 'joins' => [],
- ]
- ];
- yield 'wgContentHandlerUseDB true, wgCommentTableSchemaMigrationStage OLD' => [
- [
- 'wgContentHandlerUseDB' => true,
- 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
- ],
- [
- 'tables' => [ 'archive' ],
- 'fields' => [
- 'ar_id',
- 'ar_page_id',
- 'ar_namespace',
- 'ar_title',
- 'ar_rev_id',
- 'ar_text',
- 'ar_text_id',
- 'ar_timestamp',
- 'ar_user_text',
- 'ar_user',
- 'ar_minor_edit',
- 'ar_deleted',
- 'ar_len',
- 'ar_parent_id',
- 'ar_sha1',
- 'ar_comment_text' => 'ar_comment',
- 'ar_comment_data' => 'NULL',
- 'ar_comment_cid' => 'NULL',
- 'ar_content_format',
- 'ar_content_model',
- ],
- 'joins' => [],
- ]
- ];
- yield 'wgContentHandlerUseDB false, wgCommentTableSchemaMigrationStage WRITE_BOTH' => [
- [
- 'wgContentHandlerUseDB' => false,
- 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH,
- ],
- [
- 'tables' => [
- 'archive',
- 'comment_ar_comment' => 'comment',
- ],
- 'fields' => [
- 'ar_id',
- 'ar_page_id',
- 'ar_namespace',
- 'ar_title',
- 'ar_rev_id',
- 'ar_text',
- 'ar_text_id',
- 'ar_timestamp',
- 'ar_user_text',
- 'ar_user',
- 'ar_minor_edit',
- 'ar_deleted',
- 'ar_len',
- 'ar_parent_id',
- 'ar_sha1',
- 'ar_comment_text' => 'COALESCE( comment_ar_comment.comment_text, ar_comment )',
- 'ar_comment_data' => 'comment_ar_comment.comment_data',
- 'ar_comment_cid' => 'comment_ar_comment.comment_id',
- ],
- 'joins' => [
- 'comment_ar_comment' => [
- 'LEFT JOIN',
- 'comment_ar_comment.comment_id = ar_comment_id',
- ],
- ],
- ]
- ];
- yield 'wgContentHandlerUseDB false, wgCommentTableSchemaMigrationStage WRITE_NEW' => [
+ yield 'wgContentHandlerUseDB false' => [
[
'wgContentHandlerUseDB' => false,
- 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_NEW,
],
[
'tables' => [
'archive',
- 'comment_ar_comment' => 'comment',
+ 'commentstore' => 'table',
],
'fields' => [
'ar_id',
'ar_len',
'ar_parent_id',
'ar_sha1',
- 'ar_comment_text' => 'COALESCE( comment_ar_comment.comment_text, ar_comment )',
- 'ar_comment_data' => 'comment_ar_comment.comment_data',
- 'ar_comment_cid' => 'comment_ar_comment.comment_id',
- ],
- 'joins' => [
- 'comment_ar_comment' => [
- 'LEFT JOIN',
- 'comment_ar_comment.comment_id = ar_comment_id',
- ],
+ 'commentstore' => 'field'
],
+ 'joins' => [ 'commentstore' => 'join' ],
]
];
- yield 'wgContentHandlerUseDB false, wgCommentTableSchemaMigrationStage NEW' => [
+ yield 'wgContentHandlerUseDB true' => [
[
- 'wgContentHandlerUseDB' => false,
- 'wgCommentTableSchemaMigrationStage' => MIGRATION_NEW,
+ 'wgContentHandlerUseDB' => true,
],
[
'tables' => [
'archive',
- 'comment_ar_comment' => 'comment',
+ 'commentstore' => 'table',
],
'fields' => [
'ar_id',
'ar_len',
'ar_parent_id',
'ar_sha1',
- 'ar_comment_text' => 'comment_ar_comment.comment_text',
- 'ar_comment_data' => 'comment_ar_comment.comment_data',
- 'ar_comment_cid' => 'comment_ar_comment.comment_id',
- ],
- 'joins' => [
- 'comment_ar_comment' => [
- 'JOIN',
- 'comment_ar_comment.comment_id = ar_comment_id',
- ],
+ 'commentstore' => 'field',
+ 'ar_content_format',
+ 'ar_content_model',
],
+ 'joins' => [ 'commentstore' => 'join' ],
]
];
}
*/
public function testGetArchiveQueryInfo( $globals, $expected ) {
$this->setMwGlobals( $globals );
+ $this->overrideCommentStore();
$revisionStore = $this->getRevisionStore();
$revisionStore->setContentHandlerUseDB( $globals['wgContentHandlerUseDB'] );
$this->setService( 'RevisionStore', $revisionStore );
-
$this->assertEquals(
$expected,
Revision::getArchiveQueryInfo()
}
public function provideGetQueryInfo() {
- yield 'wgContentHandlerUseDB false, wgCommentTableSchemaMigrationStage OLD, opts none' => [
+ yield 'wgContentHandlerUseDB false, opts none' => [
[
'wgContentHandlerUseDB' => false,
- 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
],
[],
[
- 'tables' => [ 'revision' ],
+ 'tables' => [ 'revision', 'commentstore' => 'table' ],
'fields' => [
'rev_id',
'rev_page',
'rev_len',
'rev_parent_id',
'rev_sha1',
- 'rev_comment_text' => 'rev_comment',
- 'rev_comment_data' => 'NULL',
- 'rev_comment_cid' => 'NULL',
+ 'commentstore' => 'field',
],
- 'joins' => [],
+ 'joins' => [ 'commentstore' => 'join' ],
],
];
- yield 'wgContentHandlerUseDB false, wgCommentTableSchemaMigrationStage OLD, opts page' => [
+ yield 'wgContentHandlerUseDB false, opts page' => [
[
'wgContentHandlerUseDB' => false,
- 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
],
[ 'page' ],
[
- 'tables' => [ 'revision', 'page' ],
+ 'tables' => [ 'revision', 'commentstore' => 'table', 'page' ],
'fields' => [
'rev_id',
'rev_page',
'rev_len',
'rev_parent_id',
'rev_sha1',
- 'rev_comment_text' => 'rev_comment',
- 'rev_comment_data' => 'NULL',
- 'rev_comment_cid' => 'NULL',
+ 'commentstore' => 'field',
'page_namespace',
'page_title',
'page_id',
'INNER JOIN',
[ 'page_id = rev_page' ],
],
+ 'commentstore' => 'join',
],
],
];
- yield 'wgContentHandlerUseDB false, wgCommentTableSchemaMigrationStage OLD, opts user' => [
+ yield 'wgContentHandlerUseDB false, opts user' => [
[
'wgContentHandlerUseDB' => false,
- 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
],
[ 'user' ],
[
- 'tables' => [ 'revision', 'user' ],
+ 'tables' => [ 'revision', 'commentstore' => 'table', 'user' ],
'fields' => [
'rev_id',
'rev_page',
'rev_len',
'rev_parent_id',
'rev_sha1',
- 'rev_comment_text' => 'rev_comment',
- 'rev_comment_data' => 'NULL',
- 'rev_comment_cid' => 'NULL',
+ 'commentstore' => 'field',
'user_name',
],
'joins' => [
'user_id = rev_user',
],
],
+ 'commentstore' => 'join',
],
],
];
- yield 'wgContentHandlerUseDB false, wgCommentTableSchemaMigrationStage OLD, opts text' => [
+ yield 'wgContentHandlerUseDB false, opts text' => [
[
'wgContentHandlerUseDB' => false,
- 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
],
[ 'text' ],
[
- 'tables' => [ 'revision', 'text' ],
+ 'tables' => [ 'revision', 'commentstore' => 'table', 'text' ],
'fields' => [
'rev_id',
'rev_page',
'rev_len',
'rev_parent_id',
'rev_sha1',
- 'rev_comment_text' => 'rev_comment',
- 'rev_comment_data' => 'NULL',
- 'rev_comment_cid' => 'NULL',
+ 'commentstore' => 'field',
'old_text',
'old_flags',
],
'INNER JOIN',
[ 'rev_text_id=old_id' ],
],
+ 'commentstore' => 'join',
],
],
];
- yield 'wgContentHandlerUseDB false, wgCommentTableSchemaMigrationStage OLD, opts 3' => [
+ yield 'wgContentHandlerUseDB false, opts 3' => [
[
'wgContentHandlerUseDB' => false,
- 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
],
[ 'text', 'page', 'user' ],
[
- 'tables' => [ 'revision', 'page', 'user', 'text' ],
+ 'tables' => [ 'revision', 'commentstore' => 'table', 'page', 'user', 'text' ],
'fields' => [
'rev_id',
'rev_page',
'rev_len',
'rev_parent_id',
'rev_sha1',
- 'rev_comment_text' => 'rev_comment',
- 'rev_comment_data' => 'NULL',
- 'rev_comment_cid' => 'NULL',
+ 'commentstore' => 'field',
'page_namespace',
'page_title',
'page_id',
'INNER JOIN',
[ 'rev_text_id=old_id' ],
],
+ 'commentstore' => 'join',
],
],
];
- yield 'wgContentHandlerUseDB true, wgCommentTableSchemaMigrationStage OLD, opts none' => [
+ yield 'wgContentHandlerUseDB true, opts none' => [
[
'wgContentHandlerUseDB' => true,
- 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
],
[],
[
- 'tables' => [ 'revision' ],
+ 'tables' => [ 'revision', 'commentstore' => 'table' ],
'fields' => [
'rev_id',
'rev_page',
'rev_len',
'rev_parent_id',
'rev_sha1',
- 'rev_comment_text' => 'rev_comment',
- 'rev_comment_data' => 'NULL',
- 'rev_comment_cid' => 'NULL',
+ 'commentstore' => 'field',
'rev_content_format',
'rev_content_model',
],
- 'joins' => [],
- ],
- ];
- yield 'wgContentHandlerUseDB false, wgCommentTableSchemaMigrationStage WRITE_BOTH, opts none' => [
- [
- 'wgContentHandlerUseDB' => false,
- 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH,
- ],
- [],
- [
- 'tables' => [
- 'revision',
- 'temp_rev_comment' => 'revision_comment_temp',
- 'comment_rev_comment' => 'comment',
- ],
- 'fields' => [
- 'rev_id',
- 'rev_page',
- 'rev_text_id',
- 'rev_timestamp',
- 'rev_user_text',
- 'rev_user',
- 'rev_minor_edit',
- 'rev_deleted',
- 'rev_len',
- 'rev_parent_id',
- 'rev_sha1',
- 'rev_comment_text' => 'COALESCE( comment_rev_comment.comment_text, rev_comment )',
- 'rev_comment_data' => 'comment_rev_comment.comment_data',
- 'rev_comment_cid' => 'comment_rev_comment.comment_id',
- ],
- 'joins' => [
- 'temp_rev_comment' => [
- 'LEFT JOIN',
- 'temp_rev_comment.revcomment_rev = rev_id',
- ],
- 'comment_rev_comment' => [
- 'LEFT JOIN',
- 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id',
- ],
- ],
- ],
- ];
- yield 'wgContentHandlerUseDB false, wgCommentTableSchemaMigrationStage WRITE_NEW, opts none' => [
- [
- 'wgContentHandlerUseDB' => false,
- 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_NEW,
- ],
- [],
- [
- 'tables' => [
- 'revision',
- 'temp_rev_comment' => 'revision_comment_temp',
- 'comment_rev_comment' => 'comment',
- ],
- 'fields' => [
- 'rev_id',
- 'rev_page',
- 'rev_text_id',
- 'rev_timestamp',
- 'rev_user_text',
- 'rev_user',
- 'rev_minor_edit',
- 'rev_deleted',
- 'rev_len',
- 'rev_parent_id',
- 'rev_sha1',
- 'rev_comment_text' => 'COALESCE( comment_rev_comment.comment_text, rev_comment )',
- 'rev_comment_data' => 'comment_rev_comment.comment_data',
- 'rev_comment_cid' => 'comment_rev_comment.comment_id',
- ],
- 'joins' => [
- 'temp_rev_comment' => [
- 'LEFT JOIN',
- 'temp_rev_comment.revcomment_rev = rev_id',
- ],
- 'comment_rev_comment' => [
- 'LEFT JOIN',
- 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id',
- ],
- ],
- ],
- ];
- yield 'wgContentHandlerUseDB false, wgCommentTableSchemaMigrationStage NEW, opts none' => [
- [
- 'wgContentHandlerUseDB' => false,
- 'wgCommentTableSchemaMigrationStage' => MIGRATION_NEW,
- ],
- [],
- [
- 'tables' => [
- 'revision',
- 'temp_rev_comment' => 'revision_comment_temp',
- 'comment_rev_comment' => 'comment',
- ],
- 'fields' => [
- 'rev_id',
- 'rev_page',
- 'rev_text_id',
- 'rev_timestamp',
- 'rev_user_text',
- 'rev_user',
- 'rev_minor_edit',
- 'rev_deleted',
- 'rev_len',
- 'rev_parent_id',
- 'rev_sha1',
- 'rev_comment_text' => 'comment_rev_comment.comment_text',
- 'rev_comment_data' => 'comment_rev_comment.comment_data',
- 'rev_comment_cid' => 'comment_rev_comment.comment_id',
- ],
- 'joins' => [
- 'temp_rev_comment' => [
- 'JOIN',
- 'temp_rev_comment.revcomment_rev = rev_id',
- ],
- 'comment_rev_comment' => [
- 'JOIN',
- 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id',
- ],
- ],
+ 'joins' => [ 'commentstore' => 'join' ],
],
];
}
*/
public function testGetQueryInfo( $globals, $options, $expected ) {
$this->setMwGlobals( $globals );
+ $this->overrideCommentStore();
$revisionStore = $this->getRevisionStore();
$revisionStore->setContentHandlerUseDB( $globals['wgContentHandlerUseDB'] );
);
}
+ /**
+ * @covers Revision::getSize
+ */
+ public function testGetSize() {
+ $title = $this->getMockTitle();
+
+ $rec = new MutableRevisionRecord( $title );
+ $rev = new Revision( $rec, 0, $title );
+
+ $this->assertSame( 0, $rev->getSize(), 'Size of no slots is 0' );
+
+ $rec->setSize( 13 );
+ $this->assertSame( 13, $rev->getSize() );
+ }
+
+ /**
+ * @covers Revision::getSize
+ */
+ public function testGetSize_failure() {
+ $title = $this->getMockTitle();
+
+ $rec = $this->getMockBuilder( RevisionRecord::class )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $rec->method( 'getSize' )
+ ->willThrowException( new RevisionAccessException( 'Oops!' ) );
+
+ $rev = new Revision( $rec, 0, $title );
+ $this->assertNull( $rev->getSize() );
+ }
+
+ /**
+ * @covers Revision::getSha1
+ */
+ public function testGetSha1() {
+ $title = $this->getMockTitle();
+
+ $rec = new MutableRevisionRecord( $title );
+ $rev = new Revision( $rec, 0, $title );
+
+ $emptyHash = SlotRecord::base36Sha1( '' );
+ $this->assertSame( $emptyHash, $rev->getSha1(), 'Sha1 of no slots is hash of empty string' );
+
+ $rec->setSha1( 'deadbeef' );
+ $this->assertSame( 'deadbeef', $rev->getSha1() );
+ }
+
+ /**
+ * @covers Revision::getSha1
+ */
+ public function testGetSha1_failure() {
+ $title = $this->getMockTitle();
+
+ $rec = $this->getMockBuilder( RevisionRecord::class )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $rec->method( 'getSha1' )
+ ->willThrowException( new RevisionAccessException( 'Oops!' ) );
+
+ $rev = new Revision( $rec, 0, $title );
+ $this->assertNull( $rev->getSha1() );
+ }
+
+ /**
+ * @covers Revision::getContent
+ */
+ public function testGetContent() {
+ $title = $this->getMockTitle();
+
+ $rec = new MutableRevisionRecord( $title );
+ $rev = new Revision( $rec, 0, $title );
+
+ $this->assertNull( $rev->getContent(), 'Content of no slots is null' );
+
+ $content = new TextContent( 'Hello Kittens!' );
+ $rec->setContent( 'main', $content );
+ $this->assertSame( $content, $rev->getContent() );
+ }
+
+ /**
+ * @covers Revision::getContent
+ */
+ public function testGetContent_failure() {
+ $title = $this->getMockTitle();
+
+ $rec = $this->getMockBuilder( RevisionRecord::class )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $rec->method( 'getContent' )
+ ->willThrowException( new RevisionAccessException( 'Oops!' ) );
+
+ $rev = new Revision( $rec, 0, $title );
+ $this->assertNull( $rev->getContent() );
+ }
+
}